﻿using System;
using System.Configuration;
using System.Configuration.Provider;
using System.Web.Configuration;
using Avaxo.Scripting.Configuration;

namespace Avaxo.Scripting
{
    public static class LanguageEngine
    {
        private static Exception initializeException;
        private static bool initialized;
        private static readonly object lockObject;
        private static ILanguageEngine defaultEngine;
        private static LanguageEngineCollection engines;

        static LanguageEngine()
        {
            lockObject = new object();
            initialized = false;
            initializeException = null;
        }

        #region Properties

        public static ILanguageEngine DefaultEngine
        {
            get
            {
                Initialize();
                return defaultEngine;
            }
        }

        public static LanguageEngineCollection Engines
        {
            get
            {
                Initialize();
                return engines;
            }
        }

        #endregion

        #region Initialize

        private static void Initialize()
        {
            if ( initialized )
            {
                if ( initializeException != null )
                {
                    throw initializeException;
                }
            }
            else
            {
                if ( initializeException != null )
                {
                    throw initializeException;
                }
                lock ( lockObject )
                {
                    if ( initialized )
                    {
                        if ( initializeException != null )
                        {
                            throw initializeException;
                        }
                    }
                    else
                    {
                        try
                        {
                            LanguageEngineSection languageEngineSection = AvaxoConfigurationManager.LanguageEngine;
                            if ( ( languageEngineSection.DefaultEngine == null || languageEngineSection.Engines == null ) ||
                                 ( languageEngineSection.Engines.Count < 1 ) )
                            {
                                throw new ProviderException( "LanguangeEngine default provider not specified." );
                            }
                            engines = new LanguageEngineCollection();
                            ProvidersHelper.InstantiateProviders( languageEngineSection.Engines, engines,
                                                                  typeof ( ILanguageEngine ) );
                            defaultEngine = engines[ languageEngineSection.DefaultEngine ];
                            if ( defaultEngine == null )
                            {
                                throw new ConfigurationErrorsException(
                                    "Default LanguangeEngine not found",
                                    languageEngineSection.ElementInformation.Properties[ "defaultEngine" ].Source,
                                    languageEngineSection.ElementInformation.Properties[ "defaultEngine" ].LineNumber );
                            }
                            engines.SetReadOnly();
                        }
                        catch ( Exception exception )
                        {
                            initializeException = exception;
                            throw;
                        }
                        initialized = true;
                    }
                }
            }
        }

        #endregion
    }
}